package com.duolebo.uteped_sdk.msg;

import androidx.annotation.NonNull;

import com.duolebo.uteped_sdk.UTEPedEventHandler;
import com.duolebo.uteped_sdk.UTEPedMethodCallHandler;
import com.duolebo.uteped_sdk.utils.Const;
import com.duolebo.uteped_sdk.utils.LocationHelper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.yc.nadalsdk.bean.DeviceOperator;
import com.yc.nadalsdk.bean.DeviceOperatorConfig;
import com.yc.nadalsdk.bean.GpsParamsConfig;
import com.yc.nadalsdk.bean.Notify;
import com.yc.nadalsdk.bean.Response;
import com.yc.nadalsdk.bean.WorkOutManageInfo;
import com.yc.nadalsdk.bean.WorkoutRealTimeData;
import com.yc.nadalsdk.ble.open.UteBleConnection;
import com.yc.nadalsdk.ble.open.UteBleDevice;
import com.yc.nadalsdk.constants.NotifyType;
import com.yc.nadalsdk.listener.DeviceNotifyListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

/**
 * @Author: LiuYang
 * @Date: 2023/12/11 20:15
 * @Description:
 */
public class SportsMessage extends BaseMessage implements DeviceNotifyListener, LocationHelper.LocationChangeListener {
    private final static String PATH = "sports";

    LocationHelper locationHelper = LocationHelper.getInstance();

    /**
     * BaseCallback
     *
     * @param methodChannel methodChannel
     * @param eventHandler  eventHandler
     */
    public SportsMessage(MethodChannel methodChannel, UTEPedEventHandler eventHandler) {
        super(methodChannel, eventHandler);
    }

    @Override
    public String getPath() {
        return PATH;
    }

    @Override
    public boolean methodCallConsumed(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        if (!call.hasArgument(Const.KEY_METHOD))
            return false;

        if (super.methodCallConsumed(call, result))
            return true;

        UteBleConnection uteBleConnection = uteBleClient.getUteBleConnection();
        boolean consumed = true;
        String method = call.argument(Const.KEY_METHOD);
        assert method != null;

        Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();

        switch (method) {
            case Const.M_queryWorkOutManageInfo:
                WorkOutManageInfo info = uteBleConnection.queryWorkOutManageInfo().getData();
                result.success(objectToMap(info, true, false));
                break;
            case Const.M_setWorkOutManageInfo:
                if (call.hasArgument(Const.TYPE_LIST)) {
                    WorkOutManageInfo in = new WorkOutManageInfo();
                    List types = call.argument(Const.TYPE_LIST);
                    in.setAddedSportsList(types);
                    Response<?> woManageResp = uteBleConnection.setWorkOutManageInfo(in);

                    result.success(woManageResp.isSuccess());
                } else {
                    result.success(false);
                }
                break;
            case Const.M_setGpsParams:
                if (call.hasArgument(Const.TYPE_MAP)) {
                    String map = new Gson().toJson(call.argument(Const.TYPE_MAP), new TypeToken<Map<String, Object>>(){}.getType());
                    GpsParamsConfig config = new Gson().fromJson(map, GpsParamsConfig.class);

                    List<GpsParamsConfig> list = new ArrayList<>();
                    list.add(config);

                    Response<?> resp = uteBleConnection.setGpsParams(list);
                    result.success(resp.isSuccess());
                } else {
                    result.success(false);
                }
                break;
            case Const.M_setIsOpenWorkoutOperatorReport:
                boolean open = Boolean.TRUE.equals(call.argument(Const.KEY_ENABLE));
                Response<?> oResp = uteBleConnection.setIsOpenWorkoutOperatorReport(open);
                result.success(oResp.getErrorCode() == Const.CODE_SUCCESS);
                break;
            case Const.M_setWorkoutRealTimeData:
                if (call.hasArgument(Const.TYPE_MAP)) {
                    String map = new Gson().toJson(call.argument(Const.TYPE_MAP), new TypeToken<Map<String, Object>>(){}.getType());
                    WorkoutRealTimeData data = gson.fromJson(map, WorkoutRealTimeData.class);
                    Response<?> resp = uteBleConnection.setWorkoutRealTimeData(data);
                    result.success(resp.getErrorCode() == Const.CODE_SUCCESS);
                } else {
                    result.success(false);
                }
                break;
            case Const.M_getDeviceOperatorState:
                DeviceOperator opState = uteBleConnection.getDeviceOperatorState().getData();
                Map<String, Object> stateMap = new HashMap<>(5);
                stateMap.put("monitorState", opState.getMonitorState());
                stateMap.put("operatorType", opState.getOperatorType());
                stateMap.put("sportType", opState.getSportType());
                stateMap.put("startDate", opState.getStartDate());
                stateMap.put("workoutType", opState.getWorkoutType());
                result.success(stateMap);
                break;
            case Const.M_setDeviceOperator:
                if (call.hasArgument(Const.TYPE_MAP)) {
                    String map = new Gson().toJson(call.argument(Const.TYPE_MAP), new TypeToken<Map<String, Object>>(){}.getType());
                    DeviceOperatorConfig config = new Gson().fromJson(map, DeviceOperatorConfig.class);
                    Response<?> resp = uteBleConnection.setDeviceOperator(config);
                    result.success(resp.getErrorCode() == Const.CODE_SUCCESS);
                } else {
                    result.success(false);
                }
                break;
            case Const.M_startGpsSignal:
                locationHelper.startLocation();
                locationHelper.setLocationChangeListener(this);
                result.success(true);
                break;
            case Const.M_stopGpsSignal:
                locationHelper.stopLocation();
                result.success(true);
                break;
            default:
                consumed = false;
        }
        return consumed;
    }

    @Override
    public void onNotify(@NonNull UteBleDevice uteBleDevice, @NonNull Notify notify) {
        int type = notify.getType();
        Map<String, Object> map;
        switch (type) {
            // 2.56 设备主动上报执行状态(Device Actively Reports Operation Status)
            // 当设备端执行状态发生变化时，会通过NotifyType.WORKOUT_OPERATOR_REPORT主动上报
            case NotifyType.WORKOUT_OPERATOR_REPORT:
                map = new HashMap<>();
                map.put(Const.KEY_PATH, getPath());
                map.put(Const.KEY_METHOD, Const.M_setDeviceOperator);
                map.put(Const.KEY_VALUE, objectToMap(notify.getData(), true, false));
                eventHandler.publishEvent(map);
                break;
            // 设备端在完成一次运动后，会上报本次运动记录信息
            case NotifyType.WORKOUT_SUMMARY_REPORT:
                map = new HashMap<>();
                map.put(Const.KEY_PATH, getPath());
                map.put(Const.KEY_METHOD, Const.M_setSportOneRecord);
                map.put(Const.KEY_VALUE, objectToMap(notify.getData(), true, false));
                eventHandler.publishEvent(map);
                break;
            // 若在APP端开启运动后，设备端会主动上报实时运动数据。一些数据是APP端无法收集的，比如心率等，这些数据就需要通过设备端获取。
            // APP端在收到这些参数后，需要通过接口2.59设置联动运动实时数据再次把这些数据设置给设备端。
            case NotifyType.WORKOUT_REAL_TIME_DATE_REPORT:
                map = new HashMap<>();
                map.put(Const.KEY_PATH, getPath());
                map.put(Const.KEY_METHOD, Const.M_setWorkoutRealTimeData);
                map.put(Const.KEY_VALUE, objectToMap(notify.getData(), true, false));
                eventHandler.publishEvent(map);
                break;
            // 设备端会请求GPS参数。当设备端开启GPS运动时，需要APP端提供GPS信息。APP收到该请求后，需获取GPS信息发送给设备端，配合接口
            // 2.63设置 GPS 参数到设备 使用
            case NotifyType.GPS_DEVICE_PARAM:
                map = new HashMap<>();
                map.put(Const.KEY_PATH, getPath());
                map.put(Const.KEY_METHOD, Const.M_setGpsParams);
                map.put(Const.KEY_VALUE, objectToMap(notify.getData(), true, false));
                eventHandler.publishEvent(map);
                break;
            case NotifyType.WORKOUT_MANAGE_DATE_REPORT:
                map = new HashMap<>();

                HashMap value = new HashMap<>();
                value.put(Const.TYPE_LIST, objectToMap(notify.getData(), true, false));

                map.put(Const.KEY_PATH, getPath());
                map.put(Const.KEY_METHOD, Const.M_queryWorkOutManageInfo);
                map.put(Const.KEY_VALUE, value);
                eventHandler.publishEvent(map);
                break;
            case NotifyType.FITNESS_DATA_UPDATE:
                UTEPedMethodCallHandler utePedMethodCallHandler = UTEPedMethodCallHandler.shareInstance();
                if (utePedMethodCallHandler != null) {
                    utePedMethodCallHandler.publishLocal(Const.ACTION_SPORT_DATA_NOTIFY, "");
                }
                break;
        }
    }

    @Override
    public void onSignalChanged(int signal) {
        Map<String, Object> map = new HashMap<>();
        map.put(Const.KEY_PATH, getPath());
        map.put(Const.KEY_METHOD, Const.M_startGpsSignal);

        Map<String, Object> value = new HashMap<>(1);
        value.put("signal", signal);
        map.put(Const.KEY_VALUE, value);
        eventHandler.publishEvent(map);
    }
}
